home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Diamond Collection
/
The Diamond Collection (Software Vault)(Digital Impact).ISO
/
cdr47
/
sb16snd.zip
/
SBIO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-18
|
10KB
|
339 lines
/* Copyright 1995 by Ethan Brodsky. All rights reserved */
/* ██ SBIO.C ██████████████████████████████████████████████████████████████ */
/* ██ Interface ███████████████████████████████████████████████████████████ */
#define TRUE 1
#define FALSE 0
typedef enum {input, output} mode;
/* Interface procedures and functions */
int init_sb
(
int baseio,
char irq,
char dma16,
mode io,
unsigned int rate
);
void shutdown_sb(void);
void startio(unsigned long length);
void sethandler(void far *proc);
void getbuffer(int far **bufptr, unsigned int length);
void freebuffer(int far **bufptr);
/* Interface variables that can be changed in the background */
volatile long intcount;
volatile int done;
volatile char curblock;
volatile long samplesremaining;
/* ███ Implementation █████████████████████████████████████████████████████ */
#include <alloc.h>
#include <conio.h>
#include <dos.h>
#include <mem.h>
#include <stdlib.h>
#define lo(value) (unsigned char)((value) & 0x00FF)
#define hi(value) (unsigned char)((value) >> 8)
int resetport;
int readport;
int writeport;
int pollport;
int poll16port;
int pic_rotateport;
int pic_maskport;
int dma_maskport;
int dma_clrptrport;
int dma_modeport;
int dma_baseaddrport;
int dma_countport;
int dma_pageport;
char irq_startmask;
char irq_stopmask;
char irq_intvector;
char int_controller;
char dma_startmask;
char dma_stopmask;
char dma_mode;
void interrupt (*oldintvector)() = NULL;
int handlerinstalled;
void far *memarea = NULL; /* Twice the size of the output buffer */
int memareasize;
unsigned long buf_addr; /* 16-bit addressing */
unsigned char buf_page;
unsigned int buf_ofs;
int buf_length; /* In words */
int block_length; /* In words */
unsigned int samplingrate;
mode iomode;
void far (*handler)(void) = NULL;
/* ══ Low level sound card I/O ════════════════════════════════════════════ */
void write_dsp(unsigned char value)
{
while (inp(writeport) & 0x80); /* Wait for bit 7 to be cleared */
outp(writeport, value);
}
unsigned char read_dsp(void)
{
unsigned int value;
while (!(inp(pollport) & 0x80)); /* Wait for bit 7 to be set */
value = inp(readport);
return value;
}
int reset_dsp(void)
{
int i;
outp(resetport, 1);
outp(resetport, 0);
i = 100;
while ((read_dsp() != 0xAA) && i--);
return i;
}
/* ══ Initialization and shutdown ═════════════════════════════════════════ */
void installhandler(void); /* Prototypes for private functions */
void uninstallhandler(void);
void sb_exitproc(void);
int init_sb(int baseio, char irq, char dma16, mode io, unsigned int rate)
{
/* Sound card IO ports */
resetport = baseio + 0x006;
readport = baseio + 0x00A;
writeport = baseio + 0x00C;
pollport = baseio + 0x00E;
poll16port = baseio + 0x00F;
/* Reset DSP */
if (!reset_dsp()) return FALSE;
/* Compute interrupt ports and parameters */
if (irq < 8)
{
int_controller = 1;
pic_rotateport = 0x20;
pic_maskport = 0x21;
irq_intvector = 0x08 + irq;
}
else
{
int_controller = 2;
pic_rotateport = 0xA0;
pic_maskport = 0x21;
irq_intvector = 0x70 + irq-8;
}
irq_stopmask = 1 << (irq % 8);
irq_startmask = ~irq_stopmask;
/* Compute DMA ports and parameters */
dma_maskport = 0xD4;
dma_clrptrport = 0xD8;
dma_modeport = 0xD6;
dma_baseaddrport = 0xC0 + 4*(dma16-4);
dma_countport = 0xC2 + 4*(dma16-4);
switch(dma16)
{
case 5: dma_pageport = 0x8B; break;
case 6: dma_pageport = 0x89; break;
case 7: dma_pageport = 0x8A; break;
}
dma_stopmask = dma16-4 + 0x04; /* 000001xx */
dma_startmask = dma16-4 + 0x00; /* 000000xx */
/* Other initialization */
samplingrate = rate;
iomode = io;
switch (iomode)
{
case input: dma_mode = dma16-4 + 0x54; break; /* 010101xx */
case output: dma_mode = dma16-4 + 0x58; break; /* 010110xx */
}
installhandler(); /* Install interrupt handler */
atexit(sb_exitproc); /* Install exit procedure */
return TRUE;
}
/* ──────────────────────────────────────────────────────────────────────── */
void shutdown_sb(void)
{
if (handlerinstalled) uninstallhandler();
reset_dsp();
}
/* ════════════════════════════════════════════════════════════════════════ */
void startio(unsigned long length)
{
done = FALSE;
samplesremaining = length;
curblock = 0;
samplesremaining -= block_length;
/* Program DMA controller */
outp(dma_maskport, dma_stopmask);
outp(dma_clrptrport, 0x00);
outp(dma_modeport, dma_mode);
outp(dma_baseaddrport, lo(buf_ofs)); /* Low byte of offset */
outp(dma_baseaddrport, hi(buf_ofs)); /* High word of offset */
outp(dma_countport, lo(buf_length-1)); /* Low byte of count */
outp(dma_countport, hi(buf_length-1)); /* High byte of count */
outp(dma_pageport, buf_page);
outp(dma_maskport, dma_startmask);
/* Program sound card */
switch (iomode)
{
case input: write_dsp(0x42); break; /* Set input sampling rate */
case output: write_dsp(0x41); break; /* Set output sampling rate */
}
write_dsp(hi(samplingrate)); /* High byte of sampling rate */
write_dsp(lo(samplingrate)); /* Low byte of sampling rate */
switch (iomode)
{
case output: write_dsp(0xB6); break; /* 16-bit D->A, A/I, FIFO */
case input: write_dsp(0xBE); break; /* 16-bit A->D, A/I, FIFO */
}
write_dsp(0x10); /* DMA Mode: 16-bit signed mono */
write_dsp(lo(block_length-1)); /* Low byte of block length */
write_dsp(hi(block_length-1)); /* High byte of block length */
}
/* ══ Interrupt handling ══════════════════════════════════════════════════ */
void sethandler(void far *proc)
{
handler = proc;
}
/* ──────────────────────────────────────────────────────────────────────── */
void interrupt inthandler()
{ /* CurBlock -> Block that just finished */
intcount++;
if (handler != NULL) (*handler)();
samplesremaining -= block_length;
curblock = !curblock; /* Toggle current block */
if (samplesremaining < 0)
{
done = TRUE;
write_dsp(0xD9);
}
inp(poll16port);
outp(0x20, 0x20);
outp(0xA0, 0x20);
} /* CurBlock -> Block that just started */
/* ──────────────────────────────────────────────────────────────────────── */
void installhandler(void)
{
disable(); /* Disable interrupts */
outp(pic_maskport, (inp(pic_maskport)|irq_stopmask)); /* Mask IRQ */
oldintvector = getvect(irq_intvector); /* Save old vector */
setvect(irq_intvector, inthandler); /* Install new handler */
outp(pic_maskport, (inp(pic_maskport)&irq_startmask)); /* Unmask IRQ */
enable(); /* Reenable interupts */
handlerinstalled = TRUE;
}
/* ──────────────────────────────────────────────────────────────────────── */
void uninstallhandler(void)
{
disable(); /* Disable interrupts */
outp(pic_maskport, (inp(pic_maskport)|irq_stopmask)); /* Mask IRQ */
setvect(irq_intvector, oldintvector); /* Restore old vector */
enable(); /* Enable interrupts */
handlerinstalled = FALSE;
}
/* ══ Memory management ═══════════════════════════════════════════════════ */
unsigned long getlinearaddr(int far *p)
{
unsigned long addr;
addr = (unsigned long)FP_SEG(p)*16 + (unsigned long)FP_OFF(p);
return(addr);
}
/* ──────────────────────────────────────────────────────────────────────── */
void getbuffer(int far **bufptr, unsigned int length)
{
/* Find a block of memory that does not cross a page boundary */
memareasize = 8 * length;
if ((memarea = malloc(memareasize)) == NULL) /* Can't allocate mem? */
exit(EXIT_FAILURE); /* error */
*bufptr = (int far *)memarea; /* Pick first half */
if (((getlinearaddr(memarea) >> 1) % 65536) + length*2 > 65536)
*bufptr += 2*length; /* Pick second half to avoid crossing boundary */
/* DMA parameters */
buf_addr = getlinearaddr(*bufptr);
buf_page = buf_addr >> 16;
buf_ofs = (buf_addr >> 1) % 65536;
buf_length = length*2; block_length = length; /* In samples */
}
/* ──────────────────────────────────────────────────────────────────────── */
void freebuffer(int far **bufptr)
{
*bufptr = NULL;
free((void *)memarea);
}
/* ══ Exit shutdown ═══════════════════════════════════════════════════════ */
void sb_exitproc(void)
{
outp(0x20, 0x20); outp(0xA0, 0x20); /* Acknowledge any hanging ints */
write_dsp(0xD5); /* Pause digitized sound output */
outp(dma_maskport, dma_stopmask); /* Mask DMA channel */
if (handlerinstalled) uninstallhandler(); /* Uninstall int handler */
reset_dsp(); /* Reset SB DSP */
}